Jetpack Compose Themes
In Jetpack Compose, themes are used to define the styling and appearance of our application. Themes allow us to centralize and manage the colors, typography, and shapes used throughout our app, ensuring a consistent look and feel.
1. Define a Theme
Create a file named Theme.kt in your designsystem/theme directory.
Light Color Scheme
A light color scheme is defined using lightColorScheme, which includes various color definitions such as primary, onPrimary, tertiary, and others:
private val LightColorScheme = lightColorScheme(
primary = BRIGHT_BLUE,
onPrimary = WHITE,
tertiary = Green,
...
)
AppTheme Composable
The AppTheme composable function applies this color scheme to the app. It also configures the status and navigation bar appearances based on the provided boolean parameters. The SideEffect block is used to perform side effects in a composable function. In this case, it configures the window's appearance settings for status and navigation bars. Here's a breakdown of what each line does:
-
Retrieve the Window Object:
val window = (view.context as Activity).windowThis line gets the
windowobject from the currentActivitycontext. -
Disable Navigation Bar Contrast Enforcement:
window.isNavigationBarContrastEnforced = falseThis line disables the enforcement of contrast on the navigation bar. So that the navigation bar going to be transparent color.
-
Get Insets Controller:
val insetsController = WindowCompat.getInsetsController(window, view)This line retrieves the
insetsControllerfor managing window insets. -
Set Status Bar Appearance:
insetsController.isAppearanceLightStatusBars = !isAppearanceLightStatusBarsThis line sets the appearance of the status bar. If
isAppearanceLightStatusBarsisfalse, the status bar will have a dark appearance, and vice versa. So that you can customize status bars color. -
Set Navigation Bar Appearance:
insetsController.isAppearanceLightNavigationBars = !isAppearanceLightNavigationBarsThis line sets the appearance of the navigation bar. If
isAppearanceLightNavigationBarsisfalse, the navigation bar will have a dark appearance, and vice versa. So that you can customize navigation bars color.
@Composable
fun AppTheme(
isAppearanceLightStatusBars: Boolean = false,
isAppearanceLightNavigationBars: Boolean = false,
content: @Composable () -> Unit
) {
val view = LocalView.current
if (!view.isInEditMode) {
SideEffect {
val window = (view.context as Activity).window
window.isNavigationBarContrastEnforced = false
val insetsController = WindowCompat.getInsetsController(window, view)
insetsController.isAppearanceLightStatusBars = !isAppearanceLightStatusBars
insetsController.isAppearanceLightNavigationBars = !isAppearanceLightNavigationBars
}
}
MaterialTheme(
colorScheme = LightColorScheme
) {
...
}
}
Ripple Configuration
The CompositionLocalProvider is used to provide a custom ripple configuration within the theme, ensuring consistent ripple effects across the app:
CompositionLocalProvider(
LocalRippleConfiguration provides RippleConfiguration(color = GREY),
content = content
)
LocalEntryPadding
The LocalEntryPadding is a compositionLocal that provides default padding values, which can be accessed throughout the composables:
val LocalEntryPadding = compositionLocalOf {
PaddingValues()
}
NoRippleInteractionSource
The NoRippleInteractionSource class implements MutableInteractionSource to disable ripple effects by providing an empty flow of interactions:
class NoRippleInteractionSource : MutableInteractionSource {
override val interactions: Flow<Interaction> = emptyFlow()
override suspend fun emit(interaction: Interaction) {}
override fun tryEmit(interaction: Interaction) = true
}
AppPreview Composable
The AppPreview composable function is defined to facilitate previewing the theme in the Android Studio preview. It wraps the content in a Surface and BoxWithConstraints to provide a consistent layout environment:
@Composable
fun AppPreview(
content: @Composable BoxWithConstraintsScope.() -> Unit,
) {
AppTheme {
Surface {
BoxWithConstraints {
content()
}
}
}
}